/**
 * TManStarter.java
 * ************************** 
 * @date May 10, 2011
 * @author Michele Tamburini
 * 
 * **************************
 */
package infrastructureAPI.algorithms.instanceTools.facilities;

import gossipServices.basic.nodeDescriptors.NodeDescriptor;
import gossipServices.basic.view.PartialView;
import gossipServices.bootstraping.tman.TManFactory;
import gossipServices.bootstraping.tman.TManService;
import gossipServices.bootstraping.tman.rankingMethods.SortedRing;
import gossipServices.pss.PeerSamplingServiceAPI;
import infrastructureAPI.Requester;
import infrastructureAPI.Service;
import infrastructureAPI.APIMessages.DispatcherRequestMessage;
import infrastructureAPI.APIMessages.RequestMessage;
import infrastructureAPI.algorithms.APIFunction;
import infrastructureAPI.algorithms.GeneralAPIFunctionAlgorithm;

import java.net.InetAddress;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Vector;

import networkRmi.NetworkManager;

/**
 * Description: 
 * The TManStater class implements the {@link APIFunction} interface.
 * In fact the TManStarter is called in order to accomplish a 
 * request of overlay allocation.
 * This class is able to use the TMan factory in order to start
 * a TMan instance.
 * It needs in input a PartialView, used to initialize the TMan view,
 * and a {@link NetworkManager}, used to contact all involved nodes
 * into the TMan algorithm.
 * It also takes as input the targetViewSize which will be 
 * submitted to the ranking method.
 * It's an APIFunction because the propagation of the starting TMan
 * message is sent to all involved nodes and has to be executed from
 * the SystemDispatcher. 
 *
 */
public class TManStarter extends GeneralAPIFunctionAlgorithm {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	protected PartialView initialTManView;
	protected String subcloudID;
	protected TManService tman;
	
	/**
	 * 
	 * @param netMan: the NetworkManager used.
	 * @param targetView: the TMan view is initialized according to this view.
	 * @param targetViewSize: the final size of the view (used if you want
	 * 						to build an overlay larger in size than the actual view).
	 * @param subcloudID
	 * @param runNodesReqMsg
	 */
	public TManStarter(NetworkManager netMan, PartialView targetView, int targetViewSize,
			String subcloudID, RequestMessage runNodesReqMsg, PartialView toSend){
//		this.initialTManView =  targetView;
		this.subcloudID = subcloudID;
		RequestMessage reqMsg;
		NodeDescriptor dest;
		NodeDescriptor sender = runNodesReqMsg.getSender();
		Requester requester = runNodesReqMsg.replyTo();
		
//		sendTManStartingMessage(netMan, targetView, requester);
		/*
		 * Sending a RequestMessage to all nodes that have to 
		 * participate at the TMan algorithm.
		 */
		for(int i=0; i<toSend.size(); i++){
			dest = toSend.getAt(i);
			
			/*
			 * we execute the ranking of the view in order to send an 
			 * ordered list to each node 
			 */
			this.initialTManView = new SortedRing(targetViewSize).rank(dest, targetView);
			
			reqMsg = new DispatcherRequestMessage(sender, dest, this, requester);
			try {
				netMan.send(reqMsg, dest.getNodeAddress());
			} catch (RemoteException e) {
				e.printStackTrace();
			} catch (NotBoundException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public RequestMessage createRequestMessage(InetAddress targetAddress, 
			String targetNodeName) {
		return null;
	}

	@Override
	public List<Class<?>> requiredServices() {
		List<Class<?>> requiredListServices = new Vector<Class<?>>();
		requiredListServices.add(NetworkManager.class);
		requiredListServices.add(PeerSamplingServiceAPI.class);
		return requiredListServices;
	}

	@Override
	public Service extractSuppliedService() {
		return tman;
	}

	@Override
	public boolean requireSystemRegistration() {
		return true;
	}

	@Override
	public Service extractServiceToDeRegister() {
		return null;
	}

	@Override
	public boolean requireSystemDeRegistration() {
		return false;
	}

	@Override
	public boolean requireReply() {
		return true;
	}

	@Override
	public void run() {
		NetworkManager nm = (NetworkManager) services.get(0);
		PeerSamplingServiceAPI pss = (PeerSamplingServiceAPI) services.get(1);
		
		TManFactory tmanFact = new TManFactory(nm, pss, initialTManView, subcloudID);
		tman = tmanFact.getTMan();
		// ***
		// we have to register the TMan instance to the DispatcherSystem
//		System.out.println("New TMan instance correctly registered ");
		// ***
		System.out.println("Starting TMan subcloud: \""+subcloudID+"\""+
				" with neigbors:\n"+tman.getOverlayNeighbors());
		tman.startTMan();
		
		returnValue = true;
	}

}
